﻿// libeventDemo.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
//#include "event2/event-config.h"
#ifdef _WIN32
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
#else
#include <unistd.h>
#endif

#include "event2/event.h"
#include "event2/util.h"
#include "event2/event_compat.h"
#include "event2/event_struct.h"
#include "event2/bufferevent.h"


#include <thread>

typedef struct _eventPerIo
{
	struct event* pevent;

	int interval;

	std::chrono::steady_clock::time_point m_startT;
}eventPerIo;

static int g_timecbcount = 0;
static int  g_timecbMax = 0;
static int g_settimecount = 0;


static void
time_cb(evutil_socket_t fd, short event, void* arg)
{
	if (arg) {
		eventPerIo* pio = (eventPerIo*)arg;
		auto endtime = std::chrono::steady_clock::now();
		int diff = (int)std::chrono::duration_cast<std::chrono::milliseconds>(endtime - pio->m_startT).count();
		/*if (diff > 1015) 
		{
			struct timeval tv;
			evutil_gettimeofday(&tv, nullptr);
			printf("\ntimer event:%hd,%u:%u", event, tv.tv_sec, tv.tv_usec);
			printf("\nevent:interval =%d,diff:%d", pio->interval, diff);
		}*/
		if (diff > g_timecbMax) {
			g_timecbMax = diff;
		}
		g_timecbcount++;
		event_free(pio->pevent);
		delete pio;
	}
	else {
		struct timeval tv;
		evutil_gettimeofday(&tv, nullptr);
		printf("\ntimer,%u:%u: setcount:%d,count:%d,diffmax:%d", tv.tv_sec, tv.tv_usec, g_settimecount, g_timecbcount, g_timecbMax);
		g_timecbcount = 0;
		g_timecbMax = 0;
		g_settimecount = 0;

	}
}

#include <mutex>
#include <deque>
static struct event_base* base;
std::mutex  g_mutex;
std::deque<eventPerIo*>  g_list;
std::deque<eventPerIo*>  g_listtemp;
evutil_socket_t pair[2];

struct timeval tvtemp;
static void
setTimer_cb(evutil_socket_t fd, short event, void* arg)
{
	if (EV_TIMEOUT & event) {
		printf("\n%s: Timeout!\n", __func__);
	}

	if (EV_CLOSED & event) {
		printf("\n%s: detected socket close with success\n", __func__);
	}

	if (EV_READ & event) {
		char buf[128] = {0};
		int recvlen = recv(fd, buf, sizeof(buf), 0);
		if (recvlen < 0) {
			printf("\nrecv:%d", recvlen);
			//std::this_thread::sleep_for(std::chrono::seconds(1));
		}else if (recvlen == 0) {
			printf("\nrecv:%d", recvlen);
			//std::this_thread::sleep_for(std::chrono::seconds(1));
		}else {
			while (1) {
				g_mutex.lock();
				if (g_list.empty()) {
					g_mutex.unlock();
					break;
				}
				for (int j = 0; j < 10 && !g_list.empty(); j++) {
					g_listtemp.push_back(g_list.front());
					g_list.pop_front();
				}
				g_mutex.unlock();
				while (!g_listtemp.empty()) {
					eventPerIo* pIo = g_listtemp.front();
					g_listtemp.pop_front();

					struct event* timer2 = event_new(base, -1, 0, time_cb, (void*)pIo); //event_self_cbarg()
					pIo->pevent = timer2;
					tvtemp.tv_sec = 1;
					tvtemp.tv_usec = 0;// pIo->interval;
					event_add(timer2, &tvtemp);
				}
			}
			//printf("\nrecvlen :%d, %s", recvlen, buf);
		}
	}

	//printf("\n%s: pipe1 recv event :%x\n", __func__, event);
}


static void setTimer(int handle, int intervalUs)
{
	g_settimecount++;
	eventPerIo* pIo = new eventPerIo;
	pIo->interval = intervalUs;
	pIo->m_startT = std::chrono::steady_clock::now();

	g_mutex.lock();
	g_list.push_back(pIo);
	if (g_list.size() == 1) {
		if (send(pair[0], "a", 1, 0) < 0) {
			printf("\n send error");
		}
	}
	g_mutex.unlock();
}

static void thread_fun(void *agv)
{
	int* pagv = (int*)agv;
	printf("subthread run :%d", *pagv);
#if 1
	while (1) 
	{
		for (int i = 0; i < 1000; i++) {
			setTimer(i, 1000000);// rand() % 1000000);
		}
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
	}
#endif
#if 0
	while (1) {
		setTimer(1, 1000000);
		std::this_thread::sleep_for(std::chrono::seconds(1));
	}
#endif
	
	printf("\nsubthread end :%d", *pagv);
}
#include <ctime>
int timer_main()
{

#ifdef _WIN32
	WORD wVersionRequested;
	WSADATA wsaData;

	wVersionRequested = MAKEWORD(2, 2);

	(void)WSAStartup(wVersionRequested, &wsaData);
#endif

	
	
	base = event_base_new();

	/* Create a pair of sockets */
	if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
		printf("\nevutil_socketpair error");
		return (1);
	}
		
	/* Send some data on socket 0 and immediately close it */
	/*const char* test = "hello";
	if (send(pair[0], test, (int)strlen(test) + 1, 0) < 0) {
		printf("\n send error");
		return (1);
	}*/
	//shutdown(pair[0], 1);
	//evutil_closesocket(pair[0]);
		
	//struct event*ev = event_new(base, pair[1], EV_CLOSED | EV_TIMEOUT | EV_READ| EV_PERSIST, closed_cb, event_self_cbarg());
	//struct timeval timeoutpair = { 3, 0 };
	//event_add(ev, &timeoutpair);
	struct event*ev = event_new(base, pair[1], EV_CLOSED| EV_READ| EV_PERSIST, setTimer_cb, event_self_cbarg());
	event_add(ev, 0);

	static timeval t2;
	t2.tv_sec = 1;
	t2.tv_usec = 0;
	event* timer2 = event_new(base, -1, EV_PERSIST, time_cb, 0);
	event_add(timer2, &t2);

	int* pagb = new int(22);
	std::thread* subthread = new std::thread(thread_fun, pagb);

/* Dispatch */
	while (1) {
		int i = event_base_dispatch(base);

		printf("\nevent_base_dispatch=%d\n",i);
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
	
	return 0;
}
